<template>
  <div class="shape-style-panel">
    <div class="title">
      <span>点击替换形状</span>
      <IconDown />
    </div>
    <div class="shape-pool">
      <div class="category" v-for="item in SHAPE_LIST" :key="item.type">
        <div class="shape-list">
          <ShapeItemThumbnail class="shape-item" v-for="(shape, index) in item.children" :key="index" :shape="shape"
            @click="changeShape(shape)" />
        </div>
      </div>
    </div>

    <div class="row">
      <Select style="flex: 10;" :value="fillType" @change="value => updateFillType(value as 'fill' | 'gradient')">
        <SelectOption value="fill">纯色填充</SelectOption>
        <SelectOption value="gradient">渐变填充</SelectOption>
      </Select>
      <div style="flex: 1;"></div>
      <Popover trigger="click" v-if="fillType === 'fill'">
        <template #content>
          <ColorPicker :modelValue="fill" @update:modelValue="value => updateFill(value)" />
        </template>
        <ColorButton :color="fill" style="flex: 10;" />
      </Popover>
      <Select style="flex: 10;" :value="gradient.type"
        @change="value => updateGradient({ type: value as 'linear' | 'radial' })" v-else>
        <SelectOption value="linear">线性渐变</SelectOption>
        <SelectOption value="radial">径向渐变</SelectOption>
      </Select>
    </div>

    <template v-if="fillType === 'gradient'">
      <div class="row">
        <div style="flex: 2;">起点颜色：</div>
        <Popover trigger="click">
          <template #content>
            <ColorPicker :modelValue="gradient.color[0]"
              @update:modelValue="value => updateGradient({ color: [value, gradient.color[1]] })" />
          </template>
          <ColorButton :color="gradient.color[0]" style="flex: 3;" />
        </Popover>
      </div>
      <div class="row">
        <div style="flex: 2;">终点颜色：</div>
        <Popover trigger="click">
          <template #content>
            <ColorPicker :modelValue="gradient.color[1]"
              @update:modelValue="value => updateGradient({ color: [gradient.color[0], value] })" />
          </template>
          <ColorButton :color="gradient.color[1]" style="flex: 3;" />
        </Popover>
      </div>
      <div class="row" v-if="gradient.type === 'linear'">
        <div style="flex: 2;">渐变角度：</div>
        <Slider class="slider" :min="0" :max="360" :step="15" :value="gradient.rotate"
          @change="value => updateGradient({ rotate: value as number })" />
      </div>
    </template>

    <ElementFlip />

    <Divider />

    <template v-if="handleShapeElement.text?.content">
      <InputGroup compact class="row">
        <Select class="font-select" style="flex: 3;" :value="richTextAttrs.fontname"
          @change="value => emitRichTextCommand('fontname', value as string)">
          <template #suffixIcon>
            <IconFontSize />
          </template>
          <SelectOptGroup label="系统字体">
            <SelectOption v-for="font in availableFonts" :key="font.value" :value="font.value">
              <span :style="{ fontFamily: font.value }">{{ font.label }}</span>
            </SelectOption>
          </SelectOptGroup>
          <SelectOptGroup label="在线字体">
            <SelectOption v-for="font in WEB_FONTS" :key="font.value" :value="font.value">
              <span>{{ font.label }}</span>
            </SelectOption>
          </SelectOptGroup>
        </Select>
        <Select style="flex: 2;" :value="richTextAttrs.fontsize"
          @change="value => emitRichTextCommand('fontsize', value as string)">
          <template #suffixIcon>
            <IconAddText />
          </template>
          <SelectOption v-for="fontsize in fontSizeOptions" :key="fontsize" :value="fontsize">
            {{ fontsize }}
          </SelectOption>
        </Select>
      </InputGroup>

      <ButtonGroup class="row">
        <Popover trigger="click">
          <template #content>
            <ColorPicker :modelValue="richTextAttrs.color"
              @update:modelValue="value => emitRichTextCommand('color', value)" />
          </template>
          <Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="文字颜色">
            <TextColorButton :color="richTextAttrs.color" style="flex: 3;">
              <IconText />
            </TextColorButton>
          </Tooltip>
        </Popover>
        <Popover trigger="click">
          <template #content>
            <ColorPicker :modelValue="richTextAttrs.backcolor"
              @update:modelValue="value => emitRichTextCommand('backcolor', value)" />
          </template>
          <Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="文字高亮">
            <TextColorButton :color="richTextAttrs.backcolor" style="flex: 3;">
              <IconHighLight />
            </TextColorButton>
          </Tooltip>
        </Popover>
        <Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="增大字号">
          <Button class="font-size-btn" style="flex: 2;" @click="emitRichTextCommand('fontsize-add')">
            <IconFontSize />+
          </Button>
        </Tooltip>
        <Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="减小字号">
          <Button class="font-size-btn" style="flex: 2;" @click="emitRichTextCommand('fontsize-reduce')">
            <IconFontSize />-
          </Button>
        </Tooltip>
      </ButtonGroup>

      <CheckboxButtonGroup class="row">
        <Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="加粗">
          <CheckboxButton style="flex: 1;" :checked="richTextAttrs.bold" @click="emitRichTextCommand('bold')">
            <IconTextBold />
          </CheckboxButton>
        </Tooltip>
        <Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="斜体">
          <CheckboxButton style="flex: 1;" :checked="richTextAttrs.em" @click="emitRichTextCommand('em')">
            <IconTextItalic />
          </CheckboxButton>
        </Tooltip>
        <Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="下划线">
          <CheckboxButton style="flex: 1;" :checked="richTextAttrs.underline" @click="emitRichTextCommand('underline')">
            <IconTextUnderline />
          </CheckboxButton>
        </Tooltip>
        <Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="删除线">
          <CheckboxButton style="flex: 1;" :checked="richTextAttrs.strikethrough"
            @click="emitRichTextCommand('strikethrough')">
            <IconStrikethrough />
          </CheckboxButton>
        </Tooltip>
      </CheckboxButtonGroup>

      <CheckboxButtonGroup class="row">
        <Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="清除格式">
          <CheckboxButton style="flex: 1;" @click="emitRichTextCommand('clear')">
            <IconFormat />
          </CheckboxButton>
        </Tooltip>
        <Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="格式刷">
          <CheckboxButton style="flex: 1;" :checked="!!textFormatPainter" @click="toggleFormatPainter()">
            <IconFormatBrush />
          </CheckboxButton>
        </Tooltip>
      </CheckboxButtonGroup>

      <Divider />

      <RadioGroup class="row" button-style="solid" :value="richTextAttrs.align"
        @change="e => emitRichTextCommand('align', e.target.value)">
        <Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="左对齐">
          <RadioButton value="left" style="flex: 1;">
            <IconAlignTextLeft />
          </RadioButton>
        </Tooltip>
        <Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="居中">
          <RadioButton value="center" style="flex: 1;">
            <IconAlignTextCenter />
          </RadioButton>
        </Tooltip>
        <Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="右对齐">
          <RadioButton value="right" style="flex: 1;">
            <IconAlignTextRight />
          </RadioButton>
        </Tooltip>
      </RadioGroup>

      <RadioGroup class="row" button-style="solid" :value="textAlign" @change="e => updateTextAlign(e.target.value)">
        <Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="顶对齐">
          <RadioButton value="top" style="flex: 1;">
            <IconAlignTextTopOne />
          </RadioButton>
        </Tooltip>
        <Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="居中">
          <RadioButton value="middle" style="flex: 1;">
            <IconAlignTextMiddleOne />
          </RadioButton>
        </Tooltip>
        <Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="底对齐">
          <RadioButton value="bottom" style="flex: 1;">
            <IconAlignTextBottomOne />
          </RadioButton>
        </Tooltip>
      </RadioGroup>

      <Divider />
    </template>

    <ElementOutline />
    <Divider />
    <ElementShadow />
    <Divider />
    <ElementOpacity />
  </div>
</template>

<script lang="ts" setup>
import { Ref, ref, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { useMainStore } from '@/store/main'
import { useSlidesStore } from '@/store/slides'
import { PPTShapeElement, ShapeGradient, ShapeText } from '@/types/slides'
import { WEB_FONTS } from '@/configs/font'
import { ShapePoolItem, SHAPE_LIST, SHAPE_PATH_FORMULAS } from '@/configs/shapes'
import emitter, { EmitterEvents } from '@/utils/emitter'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import useTextFormatPainter from '@/hooks/useTextFormatPainter'

import ElementOpacity from '../common/ElementOpacity.vue'
import ElementOutline from '../common/ElementOutline.vue'
import ElementShadow from '../common/ElementShadow.vue'
import ElementFlip from '../common/ElementFlip.vue'
import ColorButton from '../common/ColorButton.vue'
import TextColorButton from '../common/TextColorButton.vue'
import CheckboxButton from '@/components/CheckboxButton.vue'
import CheckboxButtonGroup from '@/components/CheckboxButtonGroup.vue'
import ColorPicker from '@/components/ColorPicker/index.vue'
import ShapeItemThumbnail from '@/views/Editor/CanvasTool/ShapeItemThumbnail.vue'
import {
  Divider,
  Button,
  Tooltip,
  Popover,
  Slider,
  Select,
  Radio,
  Input,
} from 'ant-design-vue'
const { Group: RadioGroup, Button: RadioButton } = Radio
const { OptGroup: SelectOptGroup, Option: SelectOption } = Select
const InputGroup = Input.Group
const ButtonGroup = Button.Group

const mainStore = useMainStore()
const slidesStore = useSlidesStore()
const { handleElement, handleElementId, richTextAttrs, availableFonts, textFormatPainter } = storeToRefs(mainStore)

const handleShapeElement = handleElement as Ref<PPTShapeElement>

const fill = ref<string>('#000')
const gradient = ref<ShapeGradient>({
  type: 'linear',
  rotate: 0,
  color: ['#fff', '#fff'],
})
const fillType = ref('fill')
const textAlign = ref('middle')

watch(handleElement, () => {
  if (!handleElement.value || handleElement.value.type !== 'shape') return

  fill.value = handleElement.value.fill || '#fff'
  gradient.value = handleElement.value.gradient || { type: 'linear', rotate: 0, color: [fill.value, '#fff'] }
  fillType.value = handleElement.value.gradient ? 'gradient' : 'fill'
  textAlign.value = handleElement.value?.text?.align || 'middle'
}, { deep: true, immediate: true })

const { addHistorySnapshot } = useHistorySnapshot()
const { toggleFormatPainter } = useTextFormatPainter()

const updateElement = (props: Partial<PPTShapeElement>) => {
  slidesStore.updateElement({ id: handleElementId.value, props })
  addHistorySnapshot()
}

// 设置填充类型：渐变、纯色
const updateFillType = (type: 'gradient' | 'fill') => {
  if (type === 'fill') {
    slidesStore.removeElementProps({ id: handleElementId.value, propName: 'gradient' })
    addHistorySnapshot()
  }
  else updateElement({ gradient: gradient.value })
}

// 设置渐变填充
const updateGradient = (gradientProps: Partial<ShapeGradient>) => {
  if (!gradient.value) return
  const _gradient: ShapeGradient = { ...gradient.value, ...gradientProps }
  updateElement({ gradient: _gradient })
}

// 设置填充色
const updateFill = (value: string) => {
  updateElement({ fill: value })
}

// 修改形状
const changeShape = (shape: ShapePoolItem) => {
  const { width, height } = handleElement.value as PPTShapeElement
  const props: Partial<PPTShapeElement> = {
    viewBox: shape.viewBox,
    path: shape.path,
    special: shape.special,
  }
  if (shape.pathFormula) {
    props.pathFormula = shape.pathFormula
    props.viewBox = [width, height]

    const pathFormula = SHAPE_PATH_FORMULAS[shape.pathFormula]
    if ('editable' in pathFormula) {
      props.path = pathFormula.formula(width, height, pathFormula.defaultValue)
      props.keypoint = pathFormula.defaultValue
    }
    else props.path = pathFormula.formula(width, height)
  }
  else {
    props.pathFormula = undefined
    props.keypoint = undefined
  }
  updateElement(props)
}

const updateTextAlign = (align: 'top' | 'middle' | 'bottom') => {
  const _handleElement = handleElement.value as PPTShapeElement

  const defaultText: ShapeText = {
    content: '',
    defaultFontName: '微软雅黑',
    defaultColor: '#000',
    align: 'middle',
  }
  const _text = _handleElement.text || defaultText
  updateElement({ text: { ..._text, align } })
}

const fontSizeOptions = [
  '12px', '14px', '16px', '18px', '20px', '22px', '24px', '28px', '32px',
  '36px', '40px', '44px', '48px', '54px', '60px', '66px', '72px', '76px',
  '80px', '88px', '96px', '104px', '112px', '120px',
]

const emitRichTextCommand = (command: string, value?: string) => {
  emitter.emit(EmitterEvents.RICH_TEXT_COMMAND, { action: { command, value } })
}
</script>

<style lang="scss" scoped>
.shape-style-panel {
  user-select: none;
  height: calc(100vh - 120px);
}

.row {
  width: 100%;
  display: flex;
  align-items: center;
  margin-bottom: 10px;
}

.font-select {
  max-width: 50%;
}

.font-size-btn {
  padding: 0;
}

.slider {
  flex: 3;
}

.title {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}

.shape-pool {
  width: 235px;
  height: 190px;
  overflow: auto;
  padding: 5px;
  padding-right: 10px;
  border: 1px solid $borderColor;
  margin-bottom: 20px;
}

.shape-list {
  @include flex-grid-layout();
}

.shape-item {
  @include flex-grid-layout-children(6, 14%);

  height: 0;
  padding-bottom: 14%;
  flex-shrink: 0;
}
</style>